home *** CD-ROM | disk | FTP | other *** search
/ Computer Music Interactif…cial Edition 1999 Winter / cd 3.iso / pc / Mac / Shares / Midishare™1.68 / Development Tools / Common Lisp / MCL_PPC / Tutorial.lisp < prev   
Encoding:
Text File  |  1996-09-09  |  23.7 KB  |  583 lines

  1. ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
  2. ;;===================================================================================
  3. ;;\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
  4. ;;
  5. ;;             MIDISHARE MINI TUTORIAL
  6. ;;
  7. ;;      This file is a small guided tour for using MidiShare with MCL3.9.
  8. ;;
  9. ;; INSTRUCTIONS :
  10. ;; If MidiShare is not installed, you need to copy the "MidiShare™ 1.68ß" file
  11. ;; into your system folder (actually the control panel folder) and reboot.
  12. ;;
  13. ;; Then you need to load the "MidiShare.lisp" file (Load cmd in the Eval menu). 
  14. ;; It contains the lisp interface to MidiShare.
  15. ;;
  16. ;; Now you are ready for the guided tour. Just follows the instructions for each
  17. ;; tests starting from test 1. Don't skip any test because some of them depend of 
  18. ;; previous ones.
  19. ;;
  20. ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
  21. ;;===================================================================================
  22. ;;\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
  23.  
  24.  
  25.  
  26. ;;===================================================================================
  27. ;; test 1 : Check if MidiShare is installed
  28. ;;===================================================================================
  29. ;; First of all, an application have to make sure that MidiShare is in memory. 
  30. ;; This checking is done thanks to the MidiShare function. The result is T if 
  31. ;; MidiShare is installed and NIL otherwise. Check the Listener window for the
  32. ;; result.
  33.  
  34.  (midishare)                                               ; <== EVALUATE THIS EXPRESSION.
  35.  
  36. ;; Check the Listener window for the result.It must be T. If it is not, you must 
  37. ;; install MidiShare an reboot.
  38.  
  39. ;;===================================================================================
  40. ;; test 2 : current version of MidiShare
  41. ;;===================================================================================
  42. ;; MidiGetVersion gives the version number of MidiShare. The result must be
  43. ;; 168 or greater.
  44.  
  45.  (midigetversion)                                          ; <== EVALUATE THIS EXPRESSION.
  46.  
  47.  
  48. ;;===================================================================================
  49. ;; test 3 : how many client applications are running ?
  50. ;;===================================================================================
  51. ;; The MidiCountAppls gives the number of active Midi applications on. The result 
  52. ;; here will probably be 0. It means that no MidiShare client applications are running.
  53.  
  54.  (midicountappls)                                          ; <== EVALUATE THIS EXPRESSION.
  55.  
  56.  
  57. ;;===================================================================================
  58. ;; test 4 : register Common Lisp as a client application
  59. ;;===================================================================================
  60. ;; MidiOpen allows the recording of some information relative to the application 
  61. ;; context (its name, the value of the global data register, etc...), to allocate a 
  62. ;; reception FIFO and to attribute a unique reference number to the application. 
  63. ;; In counterpart to any MidiOpen call, the application must call the MidiClose 
  64. ;; function before leaving, by giving its reference number as an argument. 
  65. ;; MidiShare can thus be aware of the precise number of active Midi applications. 
  66.  
  67.  (defparameter *refnum* (midiopen "Common Lisp"))         ; <== EVALUATE THIS EXPRESSION.
  68.  
  69.  
  70. ;;===================================================================================
  71. ;; test 5 : how many client applications are running now?
  72. ;;===================================================================================
  73. ;; Now lets check again for the number of MidiShare client applications on activity.
  74.  
  75.  (midicountappls)                                         ; <== EVALUATE THIS EXPRESSION.
  76.  
  77. ;; The result is probably 2. Actually when the first client opens, a pseudo application 
  78. ;; with name "MidiShare" and reference number 0 is also started. You can think of it as 
  79. ;; the Midi drivers of MidiShare. For this reason we have a count of 2 client 
  80. ;; applications instead of 1. This pseudo application "MidiShare" cannot be closed
  81. ;; directly. It is closed automatically when the very last client application closes. 
  82.  
  83.  
  84. ;;===================================================================================
  85. ;; test 6 : list MidiShare client applications
  86. ;;===================================================================================
  87. ;; We are now going to list all the client applications on activity.
  88.  
  89. (defun list-appls ()
  90.   (format t "List of MidiShare client applications ~%")
  91.   (dotimes (i (MidiCountAppls))
  92.     (let ((ref (MidiGetIndAppl (1+ i))))
  93.       (format t 
  94.               " ~2d : reference number ~2d, name : '~a' ~%" 
  95.               (1+ i) ref (MidiGetName ref)))))          ; <== EVALUATE THIS DEFINITION
  96.  
  97. ;; NOTE : The MidiGetIndAppl function allows to know the reference number of any 
  98. ;; application by giving its order number (a number between 1 and MidiCountAppls).
  99. ;; The MidiGetName function gives the name of a client application from its
  100. ;; reference number.
  101.  
  102.  (list-appls)                                            ; <== EVALUATE THIS EXPRESSION.
  103.  
  104. ;; In the Listener window the result will be :
  105. ;;    ? List of MidiShare client applications 
  106. ;;      1 : reference number  0, name : 'MidiShare' 
  107. ;;      2 : reference number  1, name : 'Common Lisp' 
  108. ;;    NIL
  109.  
  110. ;; NOTE : The reference number of the pseudo application "MidiShare" is always 0.
  111.  
  112. ;;===================================================================================
  113. ;; test 7 : search for a client application with name "Common Lisp"
  114. ;;===================================================================================
  115. ;; Knowing an application name, it is possible to find its reference number using
  116. ;; the MidiGetNamedAppl function. If more than one client applications have the same
  117. ;; name the result is the reference number of the first one (the one with the smallest
  118. ;; reference number).
  119.  
  120.  (MidiGetNamedAppl "Common Lisp")            ; <== EVALUATE THIS EXPRESSION.
  121.  
  122. ;; The result here is 1, the same value stored in the *REFNUM* variable (see Test 4).
  123.  
  124.  *REFNUM*                        ; <== EVALUATE THIS EXPRESSION.
  125.  
  126. ;;===================================================================================
  127. ;; test 8 : search for a client application with name "XYZ"
  128. ;;===================================================================================
  129. ;; If we look for a non existant name the result is -4. This means that no application
  130. ;; with that name was found. Negative reference numbers are used as error codes.
  131.  
  132.  (MidiGetNamedAppl "XYZ?!")                ; <== EVALUATE THIS EXPRESSION.
  133.  
  134.  
  135. ;;===================================================================================
  136. ;; test 9 : change the name of client application "Common Lisp" to "MCL"
  137. ;;===================================================================================
  138. ;; MidiSetName allows to change the name of a client application.
  139.  
  140.  (MidiSetName (MidiGetNamedAppl "Common Lisp") "MCL")    ; <== EVALUATE THIS EXPRESSION.
  141.  
  142.  (list-appls)                        ; <== EVALUATE THIS EXPRESSION.
  143.  
  144. ;; In the Listener window the result will be :
  145. ;;    ? List of MidiShare client applications 
  146. ;;      1 : reference number  0, name : 'MidiShare' 
  147. ;;      2 : reference number  1, name : 'MCL' 
  148. ;;    NIL
  149.  
  150. ;;===================================================================================
  151. ;; test 10 : connect MCL to MidiShare
  152. ;;===================================================================================
  153. ;; For an application to be able to transmit and receive events, it must first connect
  154. ;; to some source and destination applications. The MidiConnect function is used to 
  155. ;; connect or disconnect a source and a destination. The function takes 3 arguments :
  156. ;; the reference number of the source, the reference number of the destination and a
  157. ;; boolean (T to connect and NIL to disconnect).
  158.  
  159.  (MidiConnect *refnum* 0 t)                ; <== EVALUATE THIS EXPRESSION.
  160.  
  161. ;; Now MCL will be able to send events to the pseudo application "MidiShare", i.e. the
  162. ;; Midi drivers.
  163.  
  164. ;;===================================================================================
  165. ;; test 11 : test if MCL is connected to MidiShare
  166. ;;===================================================================================
  167. ;; We can test the connections using MidiIsConnected.
  168.  
  169.  (MidiIsConnected *refnum* 0)                ; <== EVALUATE THIS EXPRESSION.
  170.  
  171. ;; The result is T meaning that MCL sends to MidiShare
  172.  
  173.  
  174.  (MidiIsConnected 0 *refnum*)                ; <== EVALUATE THIS EXPRESSION.
  175.  
  176. ;; The result is NIL meaning that MidiShare does not send to MCL
  177.  
  178.  
  179. ;;===================================================================================
  180. ;; test 12 : list the destinations of an application
  181. ;;===================================================================================
  182. ;; We can list all the destinations of an application by using MidiIsConnected for 
  183. ;; each possible destination
  184.  
  185.  (defun list-dest (ref1)
  186.    (format t 
  187.            "List of the destinations of '~a' (ref num = ~d) ~%" 
  188.            (MidiGetName ref1) ref1)
  189.    (dotimes (i (MidiCountAppls))
  190.      (let ((ref2 (MidiGetIndAppl (1+ i))))
  191.        (if (MidiIsConnected ref1 ref2)
  192.          (format t " --> '~a' (ref num = ~d) ~%"
  193.                  (MidiGetName ref2)  
  194.                  ref2)))))                ; <== EVALUATE THIS DEFINITION
  195.  
  196.  (list-dest *refnum*)                    ; <== EVALUATE THIS EXPRESSION.
  197.  
  198. ;; In the Listener window the result will be :
  199. ;;    ? List of the destinations of 'MCL' (ref num = 1) 
  200. ;;     --> 'MidiShare' (ref num = 0) 
  201. ;;    NIL
  202.  
  203.  
  204. ;;===================================================================================
  205. ;; test 13 : list the sources of an application
  206. ;;===================================================================================
  207. ;; We can list all the sources of an application by using MidiIsConnected for 
  208. ;; each possible source
  209.  
  210.  (defun list-src (ref1)
  211.    (format t 
  212.            "List of the sources of '~a' (ref num = ~d) ~%" 
  213.            (MidiGetName ref1) ref1)
  214.    (dotimes (i (MidiCountAppls))
  215.      (let ((ref2 (MidiGetIndAppl (1+ i))))
  216.        (if (MidiIsConnected ref2 ref1)
  217.          (format t " <-- '~a' (ref num = ~d) ~%"
  218.                  (MidiGetName ref2)  
  219.                  ref2)))))                ; <== EVALUATE THIS DEFINITION
  220.  
  221.  (list-src 0)                        ; <== EVALUATE THIS EXPRESSION.
  222.  
  223. ;; In the Listener window the result will be :
  224. ;;    ? List of the sources of 'MidiShare' (ref num = 0) 
  225. ;;      <-- 'MCL' (ref num = 1) 
  226. ;;    NIL
  227.  
  228.  
  229. ;;===================================================================================
  230. ;; test 14 : send a note with a pitch, a velocity and a duration in milliseconds
  231. ;;===================================================================================
  232. ;; We are now ready to send a note event. Be sure to have a Midi equipment connected
  233. ;; to the Modem port.
  234.  
  235.  (defun send-note (pitch)
  236.    (let ((event (MidiNewEv typeNote)))    ; ask for a new note event
  237.      (unless (%null-ptr-p event)    ; if the allocation was succesfull
  238.        (chan event 0)            ; set the midi channel to 0 (means channel 1)
  239.        (port event 0)            ; set the destination port to Modem
  240.        (field event 0 pitch)        ; set the pitch field
  241.        (field event 1 64)        ; set the velocity field
  242.        (field event 2 1000)        ; set the duration field to 1 second
  243.        (MidiSendIm *refnum* event))    ; send the note immediatly
  244.      ))                            ; <== EVALUATE THIS DEFINITION
  245.  
  246.  (send-note 60)                        ; <== EVALUATE THIS EXPRESSION.
  247.  
  248. ;; The note was sent to your Midi equipment. Actually two messages where sent, a keyOn
  249. ;; and a keyOn with velocity 0 after the duration of the note.
  250.  
  251. ;; IMPORTANT NOTE :
  252. ;; MidiShare includes its own memory manager to store events and sequences. MidiNewEv 
  253. ;; allocates the required memory to store the note event and returns a pointer. 
  254. ;; This space is automatically disposed by MidiShare when the event is sent. This means 
  255. ;; that once you have sent an event you MUST NOT use it anymore. In particular you 
  256. ;; MUST NOT send it a second time, free it or make a copy of it.
  257.  
  258. ;;===================================================================================
  259. ;; test 15 : send multiple notes
  260. ;;===================================================================================
  261. ;; Here is an example of how to send several copies of an event
  262.  
  263.  (defun send-multiple-notes (n pitch delay)
  264.    (let ((event (MidiNewEv typeNote))    ; ask for a new note event
  265.          (date (MidiGetTime)))        ; remember the current time
  266.      (unless (%null-ptr-p event)    ; if the allocation was succesful
  267.        (chan event 0)            ; set the midi channel to 0 (means channel 1)
  268.        (port event 0)            ; set the destination port to Modem
  269.        (field event 0 pitch)        ; set the pitch field
  270.        (field event 1 64)        ; set the velocity field
  271.        (field event 2 (- delay 1))    ; set the duration field
  272.  
  273.        (dotimes (i n)            ; loop for the requested number of events
  274.          (MidiSendAt *refnum*         ; send a copy of the original note
  275.                      (MidiCopyEv event)     
  276.                      (+ date (* i delay))))
  277.        (MidiFreeEv event) )        ; dispose the original note
  278.      ))                            ; <== EVALUATE THIS DEFINITION
  279.  
  280.  (send-multiple-notes 10 72 1000)            ; <== EVALUATE THIS EXPRESSION.
  281.  
  282.  (progn (send-multiple-notes 6 60 800)
  283.         (send-multiple-notes 8 72 600))            ; <== EVALUATE THIS EXPRESSION.
  284.  
  285. ;; NOTE : Events can be sent in the future. MidiShare internal scheduler takes care of 
  286. ;; sending them at the right time according to the specified date.
  287.  
  288. ;;===================================================================================
  289. ;; test 16 : send 'hello' lyric
  290. ;;===================================================================================
  291. ;; MidiShare defines several types of events. Some of them correspond to real Midi
  292. ;; messages, some others (like notes) are translated to Midi messages and some others
  293. ;; correspond to Midi File 1.0 data. Here is an example of sending Midi File Lyrics
  294. ;; data to another application. For this test you need to launch 'msDisplay' application
  295. ;; (in the 'MidiShare suite' folder) 
  296.  
  297. ;; Then we connect MCL to msDisplay
  298.  (MidiConnect *refnum* (MidiGetNamedAppl "msDisplay") t) ; <== EVALUATE THIS EXPRESSION.
  299.  
  300. (defun send-lyric (aString)
  301.   (let ((event (MidiNewEv typeLyric)))
  302.     (unless (%null-ptr-p event)
  303.       (chan event 0)
  304.        (port event 0)
  305.        (text event aString)        
  306.        (MidiSendIm *refnum* event)) ))            ; <== EVALUATE THIS DEFINITION
  307.  
  308.  (send-lyric "Hello")                    ; <== EVALUATE THIS EXPRESSION.
  309.  
  310. ;; msDisplay shows the 'Hello' message in its window
  311.  
  312. ;;===================================================================================
  313. ;; test 17 : send a text event
  314. ;;===================================================================================
  315. ;; Here is a more general way to send Midi File textual events 
  316.  
  317. (defun send-text (aType aString)
  318.   (let ((event (MidiNewEv aType)))
  319.     (unless (%null-ptr-p event)
  320.       (chan event 0)
  321.        (port event 0)
  322.        (text event aString)        
  323.       (MidiSendIm *refnum* event)) ))            ; <== EVALUATE THIS DEFINITION
  324.  
  325. (progn
  326.   (send-text typeText "Hello")
  327.   (send-text typeCopyright "Mozart")
  328.   (send-text typeSeqName "Concerto")
  329.   (send-text typeInstrName "Piano")
  330.   (send-text typeLyric "Hiiiiiii")
  331.   (send-text typeMarker "mark 1")
  332.   (send-text typeCuePoint "Reverb here"))        ; <== EVALUATE THIS EXPRESSION.
  333.  
  334.  
  335. ;;===================================================================================
  336. ;; test 18 : send an SMPTE offset
  337. ;;===================================================================================
  338.  
  339. (defun send-smpte-offset (format hours minutes seconds frames subframes)
  340.   (let ((event (MidiNewEv typeSMPTEOffset)))
  341.     (unless (%null-ptr-p event)
  342.       (chan event 0)
  343.       (port event 0)
  344.  
  345.       (field event 0 format)        
  346.       (field event 1 hours)        
  347.       (field event 2 minutes)        
  348.       (field event 3 seconds)        
  349.       (field event 4 frames)        
  350.       (field event 5 subframes)    
  351.     
  352.       (MidiSendIm *refnum* event)) ))            ; <== EVALUATE THIS DEFINITION
  353.  
  354. (send-smpte-offset Smpte25Fr 10 24 59 12 00)        ; <== EVALUATE THIS EXPRESSION.
  355.  
  356.  
  357. ;;===================================================================================
  358. ;; test 19 : delay and transpose incoming notes
  359. ;;===================================================================================
  360. ;; We are now going to see how to receive events. Every client application have a 
  361. ;; reception fifo where incoming events are stored. Applications can be informed
  362. ;; in real-time of incoming events using a receive alarm. But from Lisp we need to do 
  363. ;; some polling because Lisp code can't be called at interrupt level.
  364. ;; In this example, note, keyOn and keyOff events are transposed and sent with a delay. 
  365. ;; Other received events are deleted. The program loops until the mouse is clicked.
  366. ;; Be sure to have a Midi keyboard connected to the modem port.
  367.  
  368. (defun transform (transpose delay)
  369.   (MidiConnect *refnum* 0 t)            ; connect MCL to MidiShare
  370.   (MidiConnect 0 *refnum* t)            ; connect MidiShare to MCL
  371.   (MidiFlushEvs *refnum*)            ; flush old events in the rcv fifo
  372.   (loop (if (mouse-down-p) (return))        ; loop until mouse clicked
  373.         (do ((event (MidiGetEv *refnum*) (MidiGetEv *refnum*)))    ;read all the events
  374.             ((%null-ptr-p event))        ; in the rcv fifo
  375.           (if (member (type event) (list typeNote typeKeyOn typeKeyOff))
  376.             (progn                    ; note, keyOn and KeyOff events
  377.               (pitch event (+ transpose (pitch event)))    ;   are transposed
  378.               (date event (+ delay (date event)))    ;   delayed
  379.               (MidiSend *refnum* event))        ;   and sent.
  380.             (MidiFreeEv event))))            ; other events are deleted
  381.   (MidiConnect 0 *refnum* nil)            ; break the connection from MidiShare to MCL     
  382.   )                            ; <== EVALUATE THIS DEFINITION
  383.  
  384. (transform 12 1000)                    ; <== EVALUATE THIS EXPRESSION.
  385.  
  386.  
  387. ;;===================================================================================
  388. ;; test 20 : some (pseudo) realtime processing
  389. ;;===================================================================================
  390. ;; In this example we define a MCL process to receive incoming events.
  391.  
  392.  
  393. (progn
  394.  
  395.   (defun waiting-events-p (refnum)
  396.     (> (midicountevs refnum) 0))
  397.   
  398.   (defun midi-thru (refnum)
  399.     (loop
  400.       (do ((event (MidiGetEv refnum) (MidiGetEv refnum)))
  401.           ((%null-ptr-p event))
  402.         (midisendim refnum event))
  403.       (process-wait "waiting events" #'waiting-events-p refnum)))
  404.   )                                ; <== EVALUATE THESE DEFINITIONS
  405.  
  406. (defparameter *midishare-process* 
  407.   (process-run-function '(:name "midi-thru" :priority 2) #'midi-thru *refnum*))    ; <== EVALUATE THIS EXPRESSION.
  408.  
  409.  
  410.  
  411. ;;===================================================================================
  412. ;; test 21 : more (pseudo) realtime processing
  413. ;;===================================================================================
  414. ;; In this example we simultate the tasks and the receive alarms of MidiShare.  
  415.  
  416.  
  417. (progn
  418.   (defvar *gc-protect-tbl*)
  419.   
  420.   (defun make-protection-tbl (size)
  421.     "create an empty protection table"
  422.     (setq *gc-protect-tbl* (make-array size))
  423.     (dotimes (i size) (setf (aref *gc-protect-tbl* i) (+ i 1)))
  424.     (setf (aref *gc-protect-tbl* (- size 1)) nil))
  425.   
  426.   (defun protect (task)
  427.     "install a task in the protectio table and return its index"
  428.     (let ((index (aref *gc-protect-tbl* 0)))
  429.       (when index
  430.         (setf (aref *gc-protect-tbl* 0) (aref *gc-protect-tbl* index))
  431.         (setf (aref *gc-protect-tbl* index) task)
  432.         index)))
  433.   
  434.   (defun refere (index)
  435.     "return the task at index and make this index empty"
  436.     (let ((task (aref *gc-protect-tbl* index)))
  437.       (setf (aref *gc-protect-tbl* index) (aref *gc-protect-tbl* 0))
  438.       (setf (aref *gc-protect-tbl* 0) index)
  439.       task))
  440.  
  441.   (make-protection-tbl 500)
  442.   
  443.   (defpascal eval-task (:long date :word refnum :long index :long arg2 :long arg3)
  444.     "evaluate the task at index"
  445.     (declare (ignore date refnum arg2 arg3))
  446.     (let ((task (refere index)))
  447.       (when (consp task) (apply (car task) (cdr task)))))
  448.   
  449.   (defun schedule-task (date &rest task)
  450.     (MidiDTask eval-task date *refnum* (protect task) 0 0))
  451.   
  452.   ;; macro to schedule expressions
  453.   
  454.   (defmacro at (date form)
  455.     `(schedule-task ,date ,(symbol-function (car form)) ,@(cdr form)))
  456.   
  457.   (defmacro after (delay form)
  458.     `(schedule-task (+ (MidiGetTime) ,delay) ,(symbol-function (car form)) ,@(cdr form)))
  459.  
  460.   )                            ; <== EVAL THESE DEFINITIONS
  461.  
  462.  
  463.  
  464. (progn
  465.  
  466.   (defvar *rcv-alarm* nil)
  467.  
  468.   (defun waiting-events-tasks-p (refnum)
  469.     (or (> (midicountevs refnum) 0) 
  470.         (> (midicountdtasks refnum) 0)))
  471.   
  472.   (defun midi-rcv-and-tasks (refnum)
  473.     (let (*rcv-alarm*)
  474.       (loop 
  475.         (if (> (midicountevs refnum) 0)
  476.           (if *rcv-alarm*
  477.             (funcall *rcv-alarm* refnum)
  478.             (midiflushevs refnum)))
  479.         (dotimes (i (MidiCountDTasks refnum)) 
  480.           (MidiExec1DTask refnum))
  481.         (process-wait "waiting events or tasks" #'waiting-events-tasks-p refnum))))
  482.  
  483.   (defun set-rcv-alarm (process rcv-alarm)
  484.     (setf (symbol-value-in-process '*rcv-alarm* process) rcv-alarm))
  485.  
  486.   )                                ; <== EVALUATE THESE DEFINITIONS
  487.  
  488. (process-preset *midishare-process*  
  489.                 #'midi-rcv-and-tasks *refnum*)            ; <== EVALUATE THIS EXPRESSION.
  490.  
  491.  
  492.  
  493. ;;---------------------------------------------------------------------------------------------
  494. ;; examples of scheduling in the future
  495.  
  496. (after 2000 (print "Wake up !!!!"))                ; <== EVALUATE THIS EXPRESSION
  497.  
  498. (defun multi-print (n delay msg)
  499.   (let ((d (MidiGetTime)))
  500.     (dotimes (i n)
  501.       (at (+ d (* i delay)) (print msg)))))            ; <== EVALUATE THIS DEFINITION
  502.  
  503. (multi-print 10 1000 "hello")                    ; <== EVALUATE THIS EXPRESSION
  504.  
  505. (progn
  506.   (multi-print 10 1000 "hello")
  507.   (multi-print 5 2000 "goodby"))                ; <== EVALUATE THIS EXPRESSION
  508.  
  509.  
  510. ;;---------------------------------------------------------------------------------------------
  511. ;; examples of receive alarms
  512.  
  513. (defun transpodelay (transpose delay)
  514.   #'(lambda (refnum)
  515.       (do ((event (MidiGetEv refnum) (MidiGetEv refnum)))
  516.           ((%null-ptr-p event))
  517.         
  518.         (if (member (type event) (list typeNote typeKeyOn typeKeyOff))
  519.           (progn
  520.             (pitch event (+ transpose (pitch event)))
  521.             (date event (+ delay (date event)))
  522.             (MidiSend *refnum* event))
  523.           (MidiFreeEv event)))))                ; <== EVALUATE THIS DEFINITION
  524.  
  525. (defun echo (delay attenuation)
  526.   #'(lambda (refnum)
  527.       (do ((event (MidiGetEv refnum) (MidiGetEv refnum)))
  528.           ((%null-ptr-p event))
  529.         
  530.         (when (or (and (= (type event) typeKeyOn) (> (vel event) 0))
  531.                   (= (type event) typeNote))
  532.           (do ((dt (+ (date event) delay) (+ dt delay))
  533.                (vl (- (vel event) attenuation) (- vl attenuation))
  534.                (note ))
  535.               ((or (< vl 1)(> vl 127)))
  536.             (unless (%null-ptr-p (setq note (MidiNewEv typeNote)))
  537.               (port note (port event))
  538.               (chan note (chan event))
  539.               (pitch note (pitch event))
  540.               (vel note vl)
  541.               (dur note (- delay 1))
  542.               (MidiSendAt *refnum* note dt))))
  543.         (MidiFreeEv event))))                ; <== EVALUATE THIS DEFINITION
  544.  
  545.  
  546. ;;---------------------------------------------------------------------------------------------
  547. ;; Now we can try these receive alarms
  548.  
  549. (set-rcv-alarm *midishare-process* 
  550.                (transpodelay 12 2000))                ; <== EVALUATE THIS EXPRESSION
  551.  
  552.  
  553. (set-rcv-alarm *midishare-process* 
  554.                (echo 250 5))                    ; <== EVALUATE THIS EXPRESSION
  555.  
  556.  
  557.  
  558.  
  559.  
  560. ;;===================================================================================
  561. ;; test 22 : close MidiShare Session
  562. ;;===================================================================================
  563.  
  564. (progn
  565.   (process-kill *midishare-process*)
  566.   (MidiClose *refnum*))                        ; <== EVALUATE THIS EXPRESSION
  567.  
  568.  
  569.  
  570.  
  571.  
  572.  
  573.  
  574.  
  575.  
  576.  
  577. (defmacro for-every-event (event refnum &body action)
  578.   `(loop 
  579.      (process-wait "waiting events" #'waiting-events-tasks-p ,refnum)
  580.      (do ((,event (MidiGetEv ,refnum) (MidiGetEv ,refnum)))    ;read all the events
  581.          ((%null-ptr-p ,event))
  582.        ,@action)))
  583.